<?php


namespace App\Repositories;


use App\Services\Tools\HelperService;
use Illuminate\Support\Facades\DB;

class RyBroadcastRetryRepository
{
    //定时重新发送融云广播消息
    public function crontabRetryBroadcast($errorRecord)
    {
        $errorIds  = $reTryIds = $successIds = [];
        $retryLog  = [];
        $isOutTime = false;
        /**
         * @var $rcService \App\Services\Tools\RongCloudService
         */
        $rcService = app('rongcloud');
        //重新发送融云广播
        foreach ($errorRecord as $record) {
            $checkRes    = $this->checkIsNeedRetry($record);
            $isRetry     = $checkRes['isRetry'];
            $isError     = $checkRes['isError'];
            $originData  = $checkRes['originData'];
            $queueRyTime = HelperService::microtime_float();
            if ($isError) {
                $retryLog[] = [
                    'log_id'         => $record['id'],
                    'origin_data'    => json_encode($originData),
                    'origin_db_data' => json_encode($record),
                    'send_res'       => 6,
                    'ry_origin_msg'  => json_encode([
                        'code' => 4000,
                        'msg'  => '数据异常无法处理'
                    ], JSON_UNESCAPED_UNICODE),
                    'queue_ry_time'  => $queueRyTime,
                ];
                $errorIds[] = $record['id'];
                continue;
            }
            if (!$isRetry) {
                continue;
            }
            //需要重试
            if ($isOutTime) { //同批有超时记录
                $retryLog[] = [
                    'log_id'         => $record['id'],
                    'origin_data'    => json_encode($originData),
                    'origin_db_data' => json_encode($record),
                    'send_res'       => 3,
                    'ry_origin_msg'  => json_encode([
                        'code' => 4000,
                        'msg'  => '同批记录融云处理超时'
                    ], JSON_UNESCAPED_UNICODE),
                    'queue_ry_time'  => $queueRyTime,
                ];
                $reTryIds[] = $record['id'];
                continue;
            }
            $senderId   = $originData['senderId'];
            $content    = json_decode($originData['content'], true);
            $objectName = $originData['objectName'];
            try {
                $result = $rcService->broadcastPush($senderId, $content, $objectName);
            } catch (\Exception $e) {
                $result = [
                    'code' => 500,
                    'msg'  => "msg" . $e->getMessage() . " code:" . $e->getCode() . " line:" . $e->getLine() . ' file:' . $e->getFile(),
                ];
            }
            $queueEndTime = HelperService::microtime_float();
            if ($queueEndTime - $queueRyTime > 5000) {    //超过5s算超时，一条超时后剩余的都直接不调用算作超时（可能服务有问题）
                $isOutTime = true;
            }
            $sendRes    = isset($result['code']) && $result['code'] == 200 ? 1 : 3;  //发送结果 1表示发送成功 2表示推送进队列待处理 3表示融云处理失败 4表示队列处理失败 5表示推送队列失败
            $retryLog[] = [
                'log_id'         => $record['id'],
                'origin_data'    => json_encode($originData),
                'origin_db_data' => json_encode($record),
                'send_res'       => $sendRes,
                'ry_origin_msg'  => json_encode($result, JSON_UNESCAPED_UNICODE),
                'queue_ry_time'  => $queueRyTime,
            ];
            if ($sendRes == 1) {
                $successIds[] = $record['id'];
            } else {
                $reTryIds[] = $record['id'];
            }
        }

        //入库
        if (!empty($errorIds)) {  //数据有误无法正常重发的
            app('model_broadcast_ry_log')->whereIn('id', $errorIds)->update([
                'retry_num' => 5,
            ]);
        }
        if (!empty($reTryIds)) {  //重试失败需要再次重试的
            app('model_broadcast_ry_log')->whereIn('id', $reTryIds)->update([
                'retry_num' => DB::raw('retry_num+1'),
            ]);
        }
        if (!empty($successIds)) {    //重试成功的
            app('model_broadcast_ry_log')->whereIn('id', $successIds)->update([
                'retry_num' => DB::raw('retry_num+1'),
                'send_res'  => 1
            ]);
        }
        if (!empty($retryLog)) {
            app('model_broadcast_ry_retry_log')->insert($retryLog);
        }
        echo " reTryIds:" . count($reTryIds) . " successIds:" . count($successIds) . " errorIds:" . count($errorIds);
    }
    //判断是否需要重试
    //1，失败后第1分钟，第5分钟，第30分钟，第60分钟，第120分钟分别推送一次，直到成功，如果第120分钟推送仍然失败，则不再处理。
    //
    //2，将重试的记录入库。
    private function checkIsNeedRetry($record)
    {
        $retryNum   = $record['retry_num'];
        $data       = $record['origin_data'];
        $uniKey     = $record['uni_key'];
        $createTime = strtotime($record['created_at']);
        $data       = empty($data) ? [] : json_decode($data, true);
        $isError    = false;
        if (empty($data)) {
            $isError = true;
        }
        $retryConfig    = [
            0 => 1 * 60,
            1 => 5 * 60,
            2 => 30 * 60,
            3 => 60 * 60,
            4 => 120 * 60,
        ];
        $retryNumToTime = $retryConfig[$retryNum] ?? 0;
        if (empty($retryNumToTime)) {
            $isRetry = false;
        } else {
            $isRetry = $createTime < time() - $retryNumToTime ? true : false;
        }
        if ($isRetry) {
            $hasRecord = app('model_broadcast_ry_log')->where('uni_key', $uniKey)->where('send_res', 1)->count();
            $hasRecord = empty($hasRecord) ? 0 : 1;
            if (!empty($hasRecord)) {  //有相同uniKey的记录状态为发送成功
                $isError = true;
            }
        }
        return [
            'isRetry'    => $isRetry, //是否重试
            'isError'    => $isError, //是否信息有误
            'originData' => $data     //原始信息
        ];
    }
}